# harmonyOS_packing.py
# 2025.8.1 (优化版 - 纯逻辑模块)
# 负责执行 HarmonyOS 相关的命令行任务

import glob
import os
import platform
import re
import shutil
import subprocess


def is_valid_project_root(path):
    """检查是否是有效的项目根目录"""
    required_files = ["build-profile.json5", "hvigorfile.ts"]
    return all(os.path.isfile(os.path.join(path, f)) for f in required_files)


def run_packing_process(root, log_func):
    """
    执行完整的编译打包流程。
    这是一个阻塞函数，应该在后台线程中调用。
    """
    errors = []
    # 注意: npm install 和 ohpm install 通常在项目设置时执行一次即可，
    # 每次打包都执行可能会很慢。这里保留原逻辑，但可根据需要优化。
    commands = [
        ["ohpm", "clean"],
        ["hvigorw", "clean"],
        ["npm", "install"],
        ["ohpm", "install"],
        ["hvigorw", "assembleHap"]
    ]

    for cmd in commands:
        try:
            log_func(f">>> {' '.join(cmd)}")
            # 在Windows上，某些命令（如npm）是.cmd文件，需要shell=True
            use_shell = platform.system() == "Windows"

            proc = subprocess.Popen(
                cmd,
                cwd=root,
                stdout=subprocess.PIPE,
                stderr=subprocess.STDOUT,
                text=True,
                shell=use_shell,
                encoding="utf-8",
                errors="ignore"
            )

            # 逐行读取日志输出
            for line in proc.stdout:
                log_func(line.rstrip())

            proc.wait()  # 等待子进程结束
            if proc.returncode != 0:
                error_msg = f"命令 '{' '.join(cmd)}' 执行失败，返回码: {proc.returncode}"
                log_func(error_msg)
                errors.append(error_msg)
                break  # 一旦出错就停止后续步骤

        except FileNotFoundError:
            error_msg = f"命令 '{cmd[0]}' 未找到，请检查系统环境变量。"
            log_func(error_msg)
            errors.append(error_msg)
            break
        except Exception as e:
            log_func(f"执行命令时发生未知错误: {e}")
            errors.append(str(e))
            break

    # 查找生成的HAP文件
    hap_files = glob.glob(
        os.path.join(root, "entry", "build", "default", "outputs", "default", "*.hap")
    )

    return {"hap_files": hap_files, "errors": errors}


def check_command(cmds, arg, extra_paths=None):
    """检查命令是否可用，并返回版本和路径 (已修复编码问题)"""
    # ... shutil.which 的逻辑保持不变 ...
    for cmd in cmds:
        exe = shutil.which(cmd, path=os.pathsep.join(extra_paths) if extra_paths else None)

        if exe:
            try:
                si = subprocess.STARTUPINFO() if os.name == "nt" else None
                if si: si.dwFlags |= subprocess.STARTF_USESHOWWINDOW

                # ★★★ 关键修复点 ★★★
                # 明确指定 encoding='utf-8' 和 errors='ignore'
                r = subprocess.run(
                    [exe, arg],
                    capture_output=True,  # 使用 capture_output=True 更简洁
                    text=True,
                    timeout=5,
                    encoding="utf-8",  # 告诉 Python 使用 UTF-8 解码
                    errors="ignore",  # 如果遇到极罕见的无效字符，直接忽略
                    startupinfo=si
                )

                # 同时检查 stdout 和 stderr，因为有些工具会把版本信息输出到 stderr
                output_text = (r.stdout or r.stderr or "").strip()
                if not output_text:
                    return "✅ 已找到", "版本未知", exe

                # 提取第一行作为版本信息
                first_line = output_text.splitlines()[0]
                return "✅ 已安装", first_line, exe

            except Exception as e:
                # 即使版本获取失败，命令本身是存在的
                return "✅ 已找到", f"版本获取失败 ({type(e).__name__})", exe

    return "❌ 未找到", "", ""


def get_connected_devices():
    """获取所有已连接的设备列表"""
    hdc_path = shutil.which("hdc")
    if not hdc_path:
        return [{"error": "未找到 hdc 工具，请检查 SDK 或环境变量配置"}]

    try:
        si = subprocess.STARTUPINFO() if os.name == "nt" else None
        if si: si.dwFlags |= subprocess.STARTF_USESHOWWINDOW

        cmd = [hdc_path, "list", "targets", "-v"]
        result = subprocess.run(
            cmd, capture_output=True, text=True, timeout=10,
            encoding="utf-8", errors="ignore", startupinfo=si
        )

        if result.returncode != 0:
            error_msg = result.stderr.strip() or "hdc 命令执行失败"
            return [{"error": f"命令执行错误: {error_msg}"}]

        # 解析设备输出
        lines = result.stdout.strip().splitlines()
        # 跳过第一行标题 "List of attached devices"
        if lines and "List of attached devices" in lines[0]:
            lines = lines[1:]

        if not lines:
            return []  # 返回空列表表示没有设备，而不是错误

        devices = []
        for line in lines:
            parts = re.split(r'\s+', line.strip())
            if len(parts) >= 3:
                devices.append({
                    "sn": parts[0],
                    "type": parts[1],
                    "status": parts[2],
                    "details": " ".join(parts[3:])
                })
        return devices

    except subprocess.TimeoutExpired:
        return [{"error": "获取设备列表超时 (10s)，hdc 可能无响应"}]
    except Exception as e:
        return [{"error": f"获取设备列表时发生未知错误: {e}"}]


def install_hap_package(device_sn, hap_path):
    """
    为指定设备安装 HAP 包。
    这是一个阻塞函数，应该在后台线程中调用。
    :return: 一个包含执行结果的字符串
    """
    hdc_path = shutil.which("hdc")
    if not hdc_path:
        return '未找到 hdc 工具，请检查 SDK 或环境变量配置'

    # 确保 hap_path 是绝对路径
    hap_path = os.path.abspath(hap_path)

    # 检查文件是否存在
    if not os.path.exists(hap_path):
        return f'文件不存在: {hap_path}'

    try:
        command = [hdc_path, 'install', device_sn, hap_path]
        print(f"正在执行命令: {' '.join(command)}")

        si = subprocess.STARTUPINFO() if os.name == "nt" else None
        if si:
            si.dwFlags |= subprocess.STARTF_USESHOWWINDOW

        result = subprocess.run(
            command, capture_output=True, text=True,
            encoding='utf-8', errors='ignore', startupinfo=si
        )

        return f"执行结果:\nstdout:\n{result.stdout}\nstderr:\n{result.stderr}"

    except Exception as e:
        return f"执行 hdc install 命令时发生错误: {e}"